/**
 * Copyright (C) 2011 Audit Logger Project. All rights reserved.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.auditlogger.cli;

import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import javax.crypto.SecretKey;

import org.auditlogger.config.ConfigurationServices;
import org.auditlogger.config.spi.PropertiesConfigurator;
import org.auditlogger.security.EncryptionHelper;
import org.auditlogger.util.Base64EncoderDecoder;

/**
 * This is a command line utility to generate master key and salt for
 * 
 * @author Ravi Sharda	
 */
public class MasterKeyGenerator {
	private static PropertiesConfigurator config = ConfigurationServices.getPropertiesConfigurator();
	
	public static void main (String[] args) throws NoSuchAlgorithmException {
		System.out.println( "Generating a new secret master key" );
		System.out.println( "Available ciphers: " );
		//printSecurityProviders();
		generateMasterKey();
	}

	@SuppressWarnings("unused")
	private static void printSecurityProviders() {
		Provider[] providers = Security.getProviders();
		TreeMap<String, String> tm = new TreeMap<String, String>();
		
		for (int i = 0; i != providers.length; i++) {
			// DISCUSS: Print security provider name here???
				// Note: For some odd reason, Provider.keySet() returns
				//		 Set<Object> of the property keys (which are Strings)
				//		 contained in this provider, but Set<String> seems
				//		 more appropriate. But that's why we need the cast below.
            System.out.println("===== Provider " + i + ":" + providers[i].getName() + " ======");
			Iterator<Object> it = providers[i].keySet().iterator();
			while (it.hasNext()) {
				String key = (String)it.next();
	            String value = providers[i].getProperty( key );
	            tm.put(key, value);
                System.out.println("\t\t   " + key + " -> "+ value );
			}
		}
		Set< Entry<String,String> > keyValueSet = tm.entrySet();
		Iterator<Entry<String, String>> it = keyValueSet.iterator();
		while( it.hasNext() ) {
			Map.Entry<String,String> entry = it.next();
			String key = entry.getKey();
			String value = entry.getValue();
        	System.out.println( "   " + key + " -> "+ value );
		}
	}
	
	private static void generateMasterKey() throws NoSuchAlgorithmException {
		String encryptAlgorithm = config.defaultEncryptionAlgorithm();
		int encryptionKeyLength = config.defaultEncryptionKeyLength();
		String randomAlgorithm = config.defaultRandomAlgorithm();
		
		SecureRandom random = null;
	    random = SecureRandom.getInstance(randomAlgorithm);
		SecretKey secretKey = EncryptionHelper.generateSecretKey(encryptAlgorithm, 
				encryptionKeyLength);
        byte[] raw = secretKey.getEncoded();
        byte[] salt = new byte[20];	// Or 160-bits; big enough for SHA1, but not SHA-256 or SHA-512.
        
        random.nextBytes( salt );
        
        String eol = System.getProperty("line.separator", "\n"); // So it works on Windows too.
        System.out.println( eol + "Copy and paste these lines into your configuration.properties" + eol);
        System.out.println( "#==============================================================");
        System.out.println( "Encryptor.MasterKey=" + Base64EncoderDecoder.encodeForBase64(raw) );
        System.out.println( "Encryptor.MasterSalt=" + Base64EncoderDecoder.encodeForBase64(salt) );
        System.out.println( "#==============================================================" + eol);
	}

}
